package com.youlai.boot.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.core.security.util.SecurityUtils;
import com.youlai.boot.system.enums.OrderEnum;
import com.youlai.boot.system.mapper.ProductMapper;
import com.youlai.boot.system.mapper.UserMapper;
import com.youlai.boot.system.mapper.UserPointsMapper;
import com.youlai.boot.system.model.dto.ProductDTO;
import com.youlai.boot.system.model.dto.ShoppingInfo;
import com.youlai.boot.system.model.entity.OrderDetail;
import com.youlai.boot.system.model.entity.Product;
import com.youlai.boot.system.model.entity.UserPoints;
import com.youlai.boot.system.service.OrderDetailService;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.system.mapper.OrderMapper;
import com.youlai.boot.system.service.OrderService;
import com.youlai.boot.system.model.entity.Order;
import com.youlai.boot.system.model.form.OrderForm;
import com.youlai.boot.system.model.query.OrderQuery;
import com.youlai.boot.system.model.vo.OrderVO;
import com.youlai.boot.system.converter.OrderConverter;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 订单管理服务实现类
 *
 * @author zhangyurun
 * @since 2025-03-20 20:33
 */
@Service
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    private final OrderDetailService orderDetailService;

    private final ProductMapper productMapper;

    private final OrderMapper orderMapper;

    private final UserPointsMapper userPointsMapper;

    private final OrderConverter orderConverter;

    private final UserMapper userMapper;

    private final RedissonClient redissonClient;
    /**
     * 获取订单管理分页列表
     *
     * @param queryParams 查询参数
     * @return {@link IPage<OrderVO>} 订单管理分页列表
     */
    @Override
    public IPage<OrderVO> getOrderPage(OrderQuery queryParams) {
        Page<OrderVO> pageVO = this.baseMapper.getOrderPage(
                new Page<>(queryParams.getPageNum(), queryParams.getPageSize()),
                queryParams);
        List<Long> orderIds = pageVO.getRecords().stream().map(OrderVO::getId).toList();
        if (CollUtil.isNotEmpty(orderIds)) {
            // 使用Stream API直接生成订单商品数量映射
            Map<Long, Integer> orderDetailMap = orderDetailService.list(
                    new LambdaQueryWrapper<OrderDetail>()
                            .select(OrderDetail::getOrderId, OrderDetail::getQuantity)
                            .in(OrderDetail::getOrderId, orderIds))
                    .stream()
                    .collect(Collectors.groupingBy(
                            OrderDetail::getOrderId,
                            Collectors.summingInt(OrderDetail::getQuantity)));

            // 直接遍历VO设置总数
            pageVO.getRecords().forEach(vo -> vo.setProductQuantity(orderDetailMap.getOrDefault(vo.getId(), 0)));
        }
        return pageVO;
    }

    /**
     * 获取订单管理表单数据
     * 
     * /**
     * 获取订单管理表单数据
     *
     * @param id 订单管理ID
     * @return
     */
    @Override
    public OrderForm getOrderFormData(Long id) {
        Order entity = this.getById(id);
        return orderConverter.toForm(entity);
    }

    /**
     * 新增订单管理
     *
     * @param formData 订单管理表单对象
     * @return
     */
    @Override
    public boolean saveOrder(OrderForm formData) {
        Order entity = orderConverter.toEntity(formData);
        return this.save(entity);
    }

    /**
     * 更新订单管理
     *
     * @param id       订单管理ID
     * @param formData 订单管理表单对象
     * @return
     */
    @Override
    public boolean updateOrder(Long id, OrderForm formData) {
        Order entity = orderConverter.toEntity(formData);
        if (ObjectUtil.isNotNull(entity.getCourierId())) {
            entity.setCourierName(userMapper.selectById(entity.getCourierId()).getUsername());
        }
        return this.updateById(entity);
    }

    /**
     * 删除订单管理
     *
     * @param ids 订单管理ID，多个以英文逗号(,)分割
     * @return
     */
    @Override
    public boolean deleteOrders(String ids) {
        Assert.isTrue(StrUtil.isNotBlank(ids), "删除的订单管理数据为空");
        // 逻辑删除
        List<Long> idList = Arrays.stream(ids.split(","))
                .map(Long::parseLong)
                .toList();
        return this.removeByIds(idList);
    }

    /**
     * 购物车生成订单
     *
     * @param shoppingInfo
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long generateOrder(ShoppingInfo shoppingInfo) {
        // 1.创建订单
        Order order = Order.builder()
                .userId(SecurityUtils.getUserId())
                .username(SecurityUtils.getUsername())
                .totalPoints(shoppingInfo.getTotalPoints())
                .mobile(StrUtil.isNotBlank(shoppingInfo.getMobile()) ? shoppingInfo.getMobile() : "")
                .province(CollUtil.isNotEmpty(shoppingInfo.getArea()) ? shoppingInfo.getArea().get(0) : "")
                .city(CollUtil.size(shoppingInfo.getArea()) >= 1 ? shoppingInfo.getArea().get(1) : "")
                .country(CollUtil.size(shoppingInfo.getArea()) >= 2 ? shoppingInfo.getArea().get(2) : "")
                .address(StrUtil.isNotBlank(shoppingInfo.getAddress()) ? shoppingInfo.getAddress() : "")
                .status(OrderEnum.UNPAID.getCode())
                .build();
        this.save(order);
        // 2.记录订单详情
        if (CollUtil.isEmpty(shoppingInfo.getShoppingCart())) {
            throw new BusinessException("购物车为空");
        }
        ArrayList<OrderDetail> orderDetails = new ArrayList<>();
        shoppingInfo.getShoppingCart().forEach(productDTO -> {
            OrderDetail orderDetail = OrderDetail.builder()
                    .orderId(order.getId())
                    .productId(productDTO.getProductId())
                    .productName(productDTO.getProductName())
                    .pic(productDTO.getPic())
                    .quantity(productDTO.getQuantity())
                    .costPoints(productDTO.getCostPoints())
                    .build();
            orderDetails.add(orderDetail);

        });
        if (CollUtil.isNotEmpty(orderDetails)) {
            orderDetailService.saveBatch(orderDetails);
        } else {
            throw new BusinessException("订单详情新增失败");
        }

        // 3.库存扣减(使用细粒度分布式锁防止超卖)
        Map<Long, Integer> quantityMap = orderDetails.stream()
                .collect(Collectors.toMap(OrderDetail::getProductId, OrderDetail::getQuantity));

        // 先检查库存是否充足
        for (Map.Entry<Long, Integer> entry : quantityMap.entrySet()) {
            Long productId = entry.getKey();
            Integer quantity = entry.getValue();

            // 查询当前库存
            Product product = productMapper.selectById(productId);
            if (product == null || product.getStock() < quantity) {
                // 回滚事务
                throw new BusinessException("商品库存不足：" + (product != null ? product.getProductName() : "未知商品"));
            }
        }

        // 获取所有需要处理的商品ID
        List<Long> productIds = new ArrayList<>(quantityMap.keySet());
        
        // 对每个商品单独加锁处理库存扣减
        for (Long productId : productIds) {
            // 为每个商品创建单独的锁键
            String lockKey = "product:stock:" + productId;
            RLock lock = redissonClient.getLock(lockKey);
            
            try {
                // 尝试获取锁，最多等待2秒，锁过期时间5秒
                boolean locked = lock.tryLock(2, 5, TimeUnit.SECONDS);
                if (!locked) {
                    throw new BusinessException("商品处理繁忙，请稍后再试");
                }
                
                // 获取锁成功后，再次查询最新库存
                Integer quantity = quantityMap.get(productId);
                Product product = productMapper.selectById(productId);
                if (product == null || product.getStock() < quantity) {
                    throw new BusinessException("商品库存不足：" + (product != null ? product.getProductName() : "未知商品"));
                }
                
                // 使用乐观锁更新库存
                int updated = productMapper.update(null, new LambdaUpdateWrapper<Product>()
                        .eq(Product::getId, productId)
                        .ge(Product::getStock, quantity) // 确保库存充足
                        .setSql("stock = stock - " + quantity));
                
                if (updated == 0) {
                    throw new BusinessException("商品[" + product.getProductName() + "]库存不足或已被修改，请重试");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new BusinessException("处理订单时被中断");
            } finally {
                // 释放锁
                if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        }

        return order.getId();
    }

    /**
     * 结算订单
     *
     * @param orderId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settleOrder(Long orderId) {
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw new BusinessException("订单不存在");
        }

        Long userId = SecurityUtils.getUserId();
        UserPoints userPoints = userPointsMapper.selectOne(
                new LambdaQueryWrapper<UserPoints>().eq(UserPoints::getUserId, userId));

        // 如果用户积分账户不存在，创建一个零积分账户
        if (userPoints == null) {
            // 在事务外调用，确保即使后续操作失败，账户创建也不会回滚
            userPoints = createUserPointsAccount(userId);
        }

        // 在单独的事务中处理积分扣减和订单状态更新
        processOrderPayment(orderId, order, userId, userPoints);
    }

    /**
     * 处理订单支付
     * 在独立事务中处理积分扣减和订单状态更新
     *
     * @param orderId    订单ID
     * @param order      订单对象
     * @param userId     用户ID
     * @param userPoints 用户积分账户
     */
    @Transactional(rollbackFor = Exception.class)
    public void processOrderPayment(Long orderId, Order order, Long userId, UserPoints userPoints) {
        // 检查积分是否足够
        if (userPoints.getRemainPoints().compareTo(order.getTotalPoints()) < 0) {
            throw new BusinessException("用户积分不足");
        }

        // 扣减积分
        int updated = userPointsMapper.update(null, new LambdaUpdateWrapper<UserPoints>()
                .eq(UserPoints::getUserId, userId)
                .eq(UserPoints::getRemainPoints, userPoints.getRemainPoints()) // 乐观锁
                .set(UserPoints::getRemainPoints, userPoints.getRemainPoints().subtract(order.getTotalPoints())));

        if (updated == 0) {
            throw new BusinessException("积分扣减失败，请重试");
        }

        // 修改订单状态
        orderMapper.update(null, new LambdaUpdateWrapper<Order>()
                .eq(Order::getId, orderId)
                .set(Order::getStatus, OrderEnum.PAID.getCode())
                .set(Order::getUpdateTime, LocalDateTime.now()));
    }

    /**
     * 发货
     *
     * @param formData
     */
    @Override
    public void shipments(OrderForm formData) {
        if (ObjectUtil.isNull(formData.getCourierId())) {
            throw new BusinessException("未选择配送人员");
        }
        orderMapper.update(null, new LambdaUpdateWrapper<Order>()
                .eq(Order::getId, formData.getId())
                .set(Order::getCourierId, formData.getCourierId())
                .set(Order::getCourierName, userMapper.selectById(formData.getCourierId()).getUsername())
                .set(Order::getStatus, OrderEnum.DELIVERED.getCode()));
    }

    /**
     * 确认收货
     *
     * @param orderId
     */
    @Override
    public void confirmReceipt(Long orderId) {
        // 确认收货 修改订单状态
        orderMapper.update(null, new LambdaUpdateWrapper<Order>()
                .eq(Order::getId, orderId)
                .set(Order::getStatus, OrderEnum.FINISHED.getCode())
                .set(Order::getUpdateTime, LocalDateTime.now()));
    }

    /**
     * 创建用户积分账户
     *
     * @param userId 用户ID
     * @return 用户积分账户
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public UserPoints createUserPointsAccount(Long userId) {
        UserPoints userPoints = UserPoints.builder()
                .userId(userId)
                .totalPoints(BigDecimal.ZERO)
                .remainPoints(BigDecimal.ZERO)
                .build();
        userPointsMapper.insert(userPoints);
        return userPointsMapper.selectOne(
                new LambdaQueryWrapper<UserPoints>().eq(UserPoints::getUserId, userId));
    }

    /**
     * 手动取消订单
     *
     * @param orderId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrder(Long orderId) {
        // 1.修改订单状态
        Order order = orderMapper.selectById(orderId);
        if (order == null) {
            throw new BusinessException("订单不存在");
        }

        orderMapper.update(null, new LambdaUpdateWrapper<Order>()
                .eq(Order::getId, orderId)
                .set(Order::getStatus, OrderEnum.CANCELLED.getCode())
                .set(Order::getUpdateTime, LocalDateTime.now()));

        // 2.回退用户积分 - 使用乐观锁确保积分回退的原子性
        UserPoints userPoints = userPointsMapper.selectOne(
                new LambdaQueryWrapper<UserPoints>().eq(UserPoints::getUserId, SecurityUtils.getUserId()));
        if (userPoints != null) {
            int updated = userPointsMapper.update(null, new LambdaUpdateWrapper<UserPoints>()
                    .eq(UserPoints::getUserId, SecurityUtils.getUserId())
                    .eq(UserPoints::getRemainPoints, userPoints.getRemainPoints()) // 乐观锁
                    .setSql("remain_points = remain_points + " + order.getTotalPoints()));

            if (updated == 0) {
                throw new BusinessException("积分回退失败，请重试");
            }
        }

        // 3.回退商品库存 - 使用CAS机制确保库存回退的原子性
        List<OrderDetail> orderDetails = orderDetailService.list(new LambdaQueryWrapper<OrderDetail>()
                .eq(OrderDetail::getOrderId, orderId));
        if (CollUtil.isNotEmpty(orderDetails)) {
            // 获取所有需要回退库存的商品ID
            List<Long> productIds = orderDetails.stream()
                    .map(OrderDetail::getProductId)
                    .collect(Collectors.toList());

            // 批量查询当前库存
            List<Product> products = productMapper.selectBatchIds(productIds);
            Map<Long, Product> productMap = products.stream()
                    .collect(Collectors.toMap(Product::getId, product -> product));

            // 使用CAS机制回退库存
            int successCount = 0;
            for (OrderDetail orderDetail : orderDetails) {
                Long productId = orderDetail.getProductId();
                Integer quantity = orderDetail.getQuantity();
                Product product = productMap.get(productId);

                if (product != null) {
                    // 使用CAS更新库存，确保库存回退的原子性
                    int updated = productMapper.update(null, new LambdaUpdateWrapper<Product>()
                            .eq(Product::getId, productId)
                            .eq(Product::getStock, product.getStock()) // 精确匹配当前库存值，实现CAS
                            .setSql("stock = stock + " + quantity));

                    if (updated > 0) {
                        successCount++;
                    } else {
                        // 如果CAS更新失败，重试一次
                        product = productMapper.selectById(productId); // 重新获取最新库存
                        updated = productMapper.update(null, new LambdaUpdateWrapper<Product>()
                                .eq(Product::getId, productId)
                                .eq(Product::getStock, product.getStock())
                                .setSql("stock = stock + " + quantity));

                        if (updated > 0) {
                            successCount++;
                        }
                    }
                }
            }

            // 检查是否所有商品都成功更新了库存
            if (successCount != orderDetails.size()) {
                throw new BusinessException("部分商品库存回退失败，请重试");
            }
        }

    }

    /**
     * 查看商品列表
     * 
     * @param orderId
     * @return
     */
    @Override
    public List<ProductDTO> viewProductList(Long orderId) {
        List<OrderDetail> orderDetails = orderDetailService.list(new LambdaQueryWrapper<OrderDetail>()
                .eq(OrderDetail::getOrderId, orderId));

        if (CollUtil.isEmpty(orderDetails)) {
            return List.of();
        }
        return BeanUtil.copyToList(orderDetails, ProductDTO.class);
    }

}
